<template>
  <div v-loading="loading" class="lab-view" >
    <div v-if="!labDesign.switch || showView">
      <lab-form v-if="!loading" :element="parentView ? viewInfo.element: element" :model-data="modelData" />
    </div>
    <el-card v-else :body-style="{ padding: '12px' }">
      <span> 设计时嵌套视图不展示 - {{ this.element.props.callCmd }}</span>
    </el-card>

    <el-dialog :visible.sync="windowVisible" center :title="windowConf.title" :width="windowConf.width" append-to-body destroy-on-close :close-on-click-modal="false" :close-on-press-escape="false">
      <lab-view v-if="windowVisible" key="windowRef" :element="windowForm" :model-data="windowData" />
    </el-dialog>
  </div>
</template>

<script>
import LabBase from "../../mixins/LabBase";
import Util from "../../utils/Util";
import LabRegister from "@/mixins/LabRegister";

export default {
  name: "LabView",
  mixins: [LabBase, LabRegister],
  provide(){
    return {
      selfRegister: this.elementRegister,
      parentView: this,
      openWindow: this.openWindow,
      closeWindow: this.closeWindow,
      findElement: this.findElement,
      elementCheck: this.elementCheck,
      viewInfo: this.viewInfo,
      queryByModel: this.queryByModel,
      saveByModel: this.saveByModel,
      removeByModel: this.removeByModel,
    }
  },
  props: {
    showView:{
      type: Boolean,
      default: false
    }
  },
  watch: {
    windowVisible(newVal){
      if (!newVal) {
        this.windowForm = {}
        this.windowData = {}
      }
    }
  },
  data() {
    return {
      loading: true,
      registerMap: {},
      windowVisible: false,
      windowConf: { title: '窗口', width: '80%'},
      windowData: {},
      windowForm: {},
      viewInfo: {}
    }
  },
  created() {
    this.loading = true
    this.$LabRender.autoFill(this.element, this)
    const { callCmd } = this.element.props
    if ((this.parentView == null || !this.labDesign.switch) && callCmd && (!this.element.elements || this.element.elements.length === 0)) {
      this.$get('/view/load/' + callCmd + "?appId=" + this.appInfo.appId)
          .then(res => {
            this.$resultMsg(this, res, '视图加载异常', true)
            if (res.code === 200 && res.data) {
              this.$Util.copyAttr(res.data, this.viewInfo, null, this)
              if (this.parentView) {
                // 非最顶层
                this.elementCheck(this.viewInfo.element)
              } else {
                this.element.elements.splice(0, this.element.elements.length)
                this.$Util.copyAttr(res.data.element, this.element, null, this)
                this.elementCheck(this.element)
                const { $labProcess } = this
                if ($labProcess && this.viewInfo.viewPrimary) {
                  const { mainValue } = $labProcess.info
                  if (mainValue) {
                    this.$set(this.modelData, this.viewInfo.viewPrimary, mainValue)
                  }
                }
              }
            }
            this.loading = false
          })
    } else {
      this.elementCheck(this.element)
      this.loading = false
    }
  },
  methods: {
    /**
     * 组件属性检查
     * @param item
     * @param prentRender 父级类型
     */
    elementCheck(item, prentRender) {
      if (item.checked) {
        return
      }
      if (!item.prentRender) {
        Reflect.set(item, 'prentRender', prentRender)
      }
      this.$LabRender.autoFill(item, this)
      if (item.elements.length > 0) {
        item.elements.forEach(ele => this.elementCheck(ele, item.render || prentRender))
      }
    },
    /**
     * 组件注册，通过组件mapper注册
     * @param el  组件dom对象实例
     */
    elementRegister(el) {
      if (this.labDesign.switch || !el || !el.element || !el.element.mapper) {
        return
      }
      const key = el.element.mapper
      const list = this.registerMap[key] || []
      const index = list.findIndex(item => item === el)
      if (index < 0) {
        list.push(el)
      } else {
        list.splice(index, 1, el)
      }
      this.$set(this.registerMap, key, list)
    },
    /**
     * 组件查找
     * @param key        唯一标识，组件mapper
     * @param matchObj   详细匹配对象，对比对象内所有属性值
     * @return {*[]|*}   查找到的组件实例集合
     */
    findElement(key, matchObj){
      if (Util.isEmpty(key) || Util.isEmpty(this.registerMap)){
        return null
      } else {
        const eles = this.registerMap[key]
        if (Util.isEmpty(eles)){
          return null
        } else if (eles.length === 1) {
          return eles[0]
        } else if (!Util.isEmpty(matchObj)){
          const props = Util.isEmpty(matchObj) ? [] : Object.keys(matchObj)
          for (let i = eles.length; i > 0; i--) {
            const item = eles[i]
            let match = false
            for (let i = 0; i < props.length; i++) {
              const value = Util.callPropValue(item, props[i])
              const matchVal = Util.callPropValue(matchObj, props[i])
              match = value === matchVal
              if (!match) {
                break
              }
            }
            if (match) {
              return item
            }
          }
        }
        return null;
      }
    },
    /**
     * 打开窗口
     * @param form    窗口渲染视图
     * @param data    窗口数据
     * @param conf    窗口配置
     */
    openWindow(form, data, conf) {
      if (!Util.isEmpty(form)) {
        Util.copyAttr(form,this.windowForm,null,this)
      }
      if (!Util.isEmpty(data)) {
        Util.copyAttr(data,this.windowData,null,this)
      }
      if (!Util.isEmpty(conf)) {
        Util.copyAttr(conf,this.windowConf,null,this)
      }
      this.windowVisible = true
    },
    /**
     * 窗口关闭
     */
    closeWindow() {
      this.windowVisible = false
      Util.cleanObj(this, this.windowData)
      Util.cleanObj(this, this.windowForm)
    },
    queryByModel(query){
      return new Promise(resolve => {
        const { callModel } = this.viewInfo
        if (this.$Util.isEmpty(callModel)) {
          this.$resultMsg(this, { msg: '未获取到业务模型'})
          resolve()
          return
        }
        query.callCmd = callModel
        this.$post('/model/queryData?appId=' + this.appInfo.appId, query).then(res => {
          resolve(res)
        })
      })
    },
    /**
     * 业务模型保存
     * @param data    数据保存
     * @param refresh    调用流程刷新
     * @return {Promise<unknown>}
     */
    saveByModel(data, refresh){
      return new Promise(resolve => {
        const { callModel } = this.viewInfo
        if (this.$Util.isEmpty(callModel)) {
          this.$resultMsg(this, { msg: '未获取到业务模型'})
          resolve()
          return
        }
        const list = this.$Util.isObj(data) ? [data] : data
        if (this.$Util.isEmpty(list)) {
          this.$resultMsg(this, { msg: '没有可保存的数据'})
          resolve()
          return
        }
        this.$post('/model/saveData?appId=' + this.appInfo.appId,{
          callCmd: callModel,
          datas: list
        }).then(res => {
          if (res.code === 200 && refresh) {
            this.refreshProcess()
                .then(result => {
                  resolve(result.code ===200 ? res : result)
                })
          } else {
            resolve(res)
          }
        })
      })
    },
    /**
     * 业务模型删除
     * @param data    数据保存
     * @param refresh    调用流程刷新
     * @return {Promise<unknown>}
     */
    removeByModel(data, refresh){
      return new Promise(resolve => {
        const { callModel } = this.viewInfo
        if (this.$Util.isEmpty(callModel)) {
          this.$resultMsg(this, { msg: '未获取到业务模型'})
          resolve()
          return
        }
        const list = this.$Util.isObj(data) ? [data] : data
        if (this.$Util.isEmpty(list)) {
          this.$resultMsg(this, { msg: '没有可保存的数据'})
          resolve()
          return
        }
        this.$confirmExecute(this,{
          url: '/model/deleteData?appId=' + this.appInfo.appId,
          method: 'post',
          data: {
            callCmd: callModel,
            datas: list
          }
        }).then(res => {
          if (res.code === 200 && refresh) {
            this.refreshProcess()
                .then(result => {
                  resolve(result.code ===200 ? res : result)
                })
          } else {
            resolve(res)
          }
        })
      })
    },
    refreshProcess() {
      return new Promise(resolve => {
        if (this.$labProcess && this.$labProcess.info.processDefId && (this.$labProcess.info.todoId || this.$labProcess.info.mainValue)) {
          this.$labProcess.refresh()
              .then(result => {
                resolve(result)
              })
        } else {
          resolve({code:200})
        }
      })
    }
  }
}
</script>

<style scoped>

</style>
